package org.chipu.jnids.display;

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import org.chipu.jnids.alert.AlertEvent;
import org.chipu.shared.interfaces.Loggeable;
import org.chipu.shared.util.singletons.Utils;

// IMPROVE Add support for percentage, time remaining, time expent...
public class TextConsole implements Console, Loggeable {
	private static final TextConsole INSTANCE = new TextConsole();
	private Logger logger = Logger.getLogger(getClass().getSimpleName());
	private final Map<String, LongTask> runningTasks = new HashMap<String, LongTask>(3);

	private TextConsole() {/**/}

	public static TextConsole getInstance() {
		return INSTANCE;
	}

	@Override
	public void setLogger(Logger logger) {
		if (logger != null)
			this.logger = logger;
	}

	@Override
	public void startProgress(String taskname, String string) {
		if (runningTasks.containsKey(taskname))
			throw new IllegalStateException("Task already running: " + taskname);
		LongTask task = new LongTask(taskname);
		runningTasks.put(taskname, task);
		logger.info("Starting long task " + taskname + ": " + string + ". Running " + runningTasks.keySet());
	}

	public void doStep(String taskname, String stepName) {
		LongTask task = runningTasks.get(taskname);
		if (task == null)
			logger.severe("No running task with name '" + taskname + "'. Running " + runningTasks.keySet());
		else
			task.doStep(stepName);
	}

	@Override
	public void doProgress(String taskname) {
		LongTask task = runningTasks.get(taskname);
		if (task == null)
			logger.severe("No running task with name '" + taskname + "'. Running " + runningTasks.keySet());
		else
			task.doProgress();
	}

	@Override
	public void endProgress(String taskname) {
		endProgress(taskname, "");
	}

	@Override
	public void endProgress(String taskname, String string) {
		// DateFormat.getTimeInstance().format(new Date(task.completed())) uses daylight saving hour, that it is not what I want
		LongTask task = runningTasks.remove(taskname);
		logger.info("\t\t" + taskname + " completed in " + task.completed() + " ms (" + Utils.toReadableTime(task.completed())
			+ "). Running " + runningTasks.keySet() + string);
	}

	// -----

	@Override
	public void addMessage(Message msg) {
		switch(msg.type) {
		case DUPLICATED:
		case IGNORED:
		case NOT_RISK:
			logger.info(msg.toString());
			break;
		default:
			logger.warning(msg.toString());
		}
	}

	@Override
	public void addMessage(AlertEvent ev, Message.Type type) {
		switch(type) {
		case DUPLICATED:
		case IGNORED:
		case NOT_RISK:
			logger.info(new Message(ev, type).toString());
			break;
		default:
			logger.warning(new Message(ev, type).toString());
		}
	}

	@Override
	public void eventReceived(AlertEvent ev, byte anormalityLevel) {
		logger.warning(anormalityLevel + "  " + new Message(ev, Message.Type.ANORMAL_ACTIVITY).toString());
	}

	private class LongTask {
		private final String name;
		private final long t;
		private int i, j;
		private long endTime;

		public LongTask(String name) {
			this.name = name;
			t = System.currentTimeMillis();
		}

		public void doStep(String stepName) {
			System.out.print("\nStep " + stepName + ": ");
		}

		public void doProgress() {
			if (i++ == 100) {
				i = 0;
				if (j++ == 100) {
					System.out.println(".");
					j = 0;
				} else
					System.out.print(".");
			}
		}

		/** @return the time taken in the task */
		public long completed() {
			if (endTime == 0) {
				System.out.println("");
				endTime = System.currentTimeMillis() - t;
			}
			return endTime;
		}
	}
}